#include <stdio.h>
#include <math.h>
#include <ctime>
#include <iostream>
#include <float.h>
#include <random>
#include "gl3w.h"
#include <GL/glut.h>
#include "Model.h"
#include "Mesh.h"
#include "vmath.h"
#include "GLSLProgram.h"

#define PI 3.1415926
int WIDTH = 1366;
int HEIGHT = 768;

#define ANGLE_STEP (0.25)
//dont change scale para
#define SCALE_X 240
#define SCALE_Y 520
#define SCALE_Z SCALE_X

#define DISTANCE 800

using namespace std;

struct vertex_t
{
    float x; float y; float z;
    vertex_t(float _1 = 0,float _2 = 0,float _3 = 0):
        x(_1),y(_2),z(_3){}
};

std::default_random_engine e;
std::uniform_real_distribution<float> random_fn(0,1);

GLfloat angle;
clock_t my_time;
GLSLProgram glslProgram;
float len = 3.0;
float x = 0.0f, y = 0.0;
float dir_x = 1.5, dir_y = 1.5;
float model_width,model_height;

#define FIX_MODEL_LEFT  (SCALE_X*minBoxX)
#define FIX_MODEL_RIGHT (SCALE_Y*maxBoxX)

float eye_z = 2000.0;

vmath::mat4 project_matrix,view_matrix;

inline float interp(float a,float b,float t)
{
    return a + (b-a)*t;
}

Model* model[3];
vertex_t Kads[3];
bool Kads_direction[3];
unsigned int frameIndex = 0;
float frameValue = 0.0;

void keyboardFunc(unsigned char c,int x,int y)
{
    (void)x,(void)(y);
    if(c == 27)
        exit(0);
}

void direction(float* dir_x,float* dir_y,float x,float y)
{
    float a = fabs(cos(angle*PI/180.0));
    float width = a*model_width;

    float a_ = -30.0*1920/(1920-1366.0);
    float b_ = -30.0/(1366.0-1902.0);

    //1366x768
    //float dis = (380-width)/1.8-45;
    float dis = (380-width)/1.8-(a_+1366*b_);
   
    //float left = x - width*0.5;;
    //float right = x + width*0.5;;
    float top = y -  model_height;
    float bottom = y + model_height;

    float left = x - width;
    float right = x + width;

    if(left < -0.5*WIDTH + dis || right > 0.5*WIDTH-dis)
    {
        *dir_x = -(*dir_x);
    }
  
  
    float yoffset = -130;;  
    if(top > HEIGHT +yoffset || bottom < -HEIGHT -yoffset)
    {
        *dir_y = -(*dir_y);
    }
}

void init()
{
    gl3wInit();

    bool ret = glslProgram.compileShader("gl.vert",GLSLShaderType::VERTEX);
    if(!ret)
    {
        std::cout<<"compile gl.vs failed\n";
        exit(0);
    }

    ret = glslProgram.compileShader("gl.frag",GLSLShaderType::FRAGMENT);
    if(!ret)
    {
        std::cout<<"compile gl.fs failed\n";
        exit(0);
    }

    ret = glslProgram.link();
    if(!ret)
    {
        std::cout<<"link failed\n";
        exit(0);
    }

    ret = glslProgram.use();
    if(!ret)
    {
        std::cout<<"use failed\n";
        exit(0);
    }

    model[0] = new Model;
    model[0]->LoadModel("./model/car.fbx");

    std::cout<<"minX "<<minBoxX<<" maxX:"<<maxBoxX<<"\n";
    std::cout<<"minY "<<minBoxY<<" maxY:"<<maxBoxY<<"\n";

    model_width = boxX*SCALE_X;//360;
    model_height = boxY*SCALE_Y;//70;

    //glEnable(GL_BLEND);
    //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);
    glDepthFunc(GL_LESS);
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_POLYGON_SMOOTH);
    glEnable(GLUT_MULTISAMPLE);

    glClearColor(0.2,0.2,0.2,0.2);

    angle = 0;
}

void display()
{
    my_time = clock();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    direction(&dir_x,&dir_y,x,y);//16

    x += dir_x*len / sqrt((dir_x * dir_x + dir_y * dir_y));
    y += dir_y*len / sqrt((dir_x * dir_x + dir_y * dir_y));

    float xoffset = -(minBoxX + maxBoxX);
    float yoffset = -(minBoxY + maxBoxY)*0.5;
    auto model_matrix = vmath::translate<float>(xoffset,yoffset,0);
    model_matrix *= vmath::translate<float>(x,y,-DISTANCE);
    model_matrix *= vmath::rotate<float>(angle,0,1,0);
    model_matrix *= vmath::scale<float>(SCALE_X,SCALE_Y,SCALE_Z);

    glslProgram.use();
    glslProgram.setUniform4x4("model_matrix",model_matrix.operator float *());

    auto mv = view_matrix*model_matrix;
    vmath::mat3 v3;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            v3[i][j] = mv[i][j];

    glslProgram.setUniform3x3("NormalMatrix",v3);

    glslProgram.setUniform4x4("project_matrix",project_matrix.operator float *());
    glslProgram.setUniform4x4("view_matrix",view_matrix.operator float *());

    model[0]->RenderModel();

    glutSwapBuffers();

    angle += ANGLE_STEP;
    glutPostRedisplay();
    my_time = clock();
}

void reshape(int w,int h)
{
    WIDTH = w;
    HEIGHT = h;
    glViewport(0,0,w,h);

    project_matrix = vmath::perspective(45,float(h)/float(w),4,6000);
    vmath::vec3 eye = { 0.f, 0.f,eye_z};
    vmath::vec3 center = { 0.f, 0.f, 0.f };
    vmath::vec3 up = { 0.f, 1.f, 0.f };
    view_matrix = vmath::lookat(eye,center,up);
}

int main(int argc,char* argv[])
{
    std::srand(std::time(0));
    dir_x = rand()%100-200;
    dir_y = rand()%100-200;

    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(WIDTH*0.8,HEIGHT*0.8);
    glutCreateWindow("demo");
    glutFullScreen();
    init();
    glutKeyboardFunc(keyboardFunc);
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutMainLoop();

    for(int i=0;i<3;i++)
        delete model[i];
    return 0;
}
